/*******************************************************************************
 * Copyright (c) 2003 Boris Pruessmann and others. All rights reserved. This
 * program and the accompanying materials are made available under the terms of
 * the Common Public License v0.5 which accompanies this distribution, and is
 * available at http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors: Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.ui.internal;

import com.google.common.collect.Lists;

import net.sourceforge.perforce.core.IP4TeamProvider;
import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.PerforceException;
import net.sourceforge.perforce.core.PerforceSynchronizer;
import net.sourceforge.perforce.ui.PerforceUIPlugin;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.IInputValidator;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.ui.IMarkerResolution;
import org.eclipse.ui.IMarkerResolutionGenerator2;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWindow;

import java.lang.reflect.InvocationTargetException;
import java.util.List;

/**
 * @version $Revision: 488 $
 * @author <a href="mailto:bpruessmann@users.sourceforge.net">Boris
 *         Pruessmann</a>
 */
public class P4AddResolutionGenerator implements IMarkerResolutionGenerator2 {
  // -------------------------------------------------------------------------
  // Public Constructors

  /** Constructor for P4AddResolutionGenerator. */
  public P4AddResolutionGenerator() {
  }

  //----------------------------------------------------------------------------
  // -- Public Methods

  public IMarkerResolution[] getResolutions(IMarker marker) {
    List<IMarkerResolution> resolutions = Lists.newArrayList();
    resolutions.add(new AddToSourceControlResolution());
    resolutions.add(new AddToIgnoreResolutionMarker());

    final IFile file = (IFile) marker.getResource();
    IContainer parent = file.getParent();
    if (!parent.equals(file.getProject())) {
      resolutions.add(new AddParentToIgnoreResolutionMarker());
    }
    final IWorkbench workbench = PerforceUIPlugin.getPlugin().getWorkbench();
    final IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();

    boolean disposeShell = false;
    Shell shell;
    if (window != null) {
      shell = window.getShell();
      resolutions.add(new AddPatternToIgnoreResolutionMarker(shell));
    }
    return resolutions.toArray(new IMarkerResolution[0]);
  }

  //----------------------------------------------------------------------------
  // - Private Methods

  protected void run(final IRunnableWithProgress runnable) throws InvocationTargetException,
      InterruptedException {
    final Exception[] exception = new Exception[] {null};
    Display.getDefault().syncExec(new Runnable() {
      public void run() {
        try {
          final IWorkbench workbench = PerforceUIPlugin.getPlugin().getWorkbench();
          final IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();

          boolean disposeShell = false;
          Shell shell;
          if (window != null) {
            shell = window.getShell();
          } else {
            Display display = Display.getCurrent();
            shell = new Shell(display);
            disposeShell = true;
          }

          new ProgressMonitorDialog(shell).run(true, true, runnable);
          if (disposeShell) {
            shell.dispose();
          }
        } catch (InterruptedException e) {
          exception[0] = e;
        } catch (InvocationTargetException e) {
          exception[0] = e;
        }
      }
    });

    if (exception[0] != null) {
      if (exception[0] instanceof InvocationTargetException) {
        throw (InvocationTargetException) exception[0];
      } else if (exception[0] instanceof InterruptedException) {
        throw (InterruptedException) exception[0];
      } else {
        throw new InvocationTargetException(exception[0]);
      }
    }
  }

  // ----------------------------------------------------------------------
  // Private Nested Classes


  /** Marker resolution that adds the marker's resource to the .p4ignore file. */
  private final class AddParentToIgnoreResolutionMarker implements IMarkerResolution {
    /** @see IMarkerResolution#getLabel() */
    public String getLabel() {
      return "Add parent to .p4ignore";
    }

    /** @see IMarkerResolution#run(IMarker) */
    public void run(IMarker marker) {
      final IFile file = (IFile) marker.getResource();
      try {
        IContainer parent = file.getParent();
        PerforceSynchronizer.getInstance().addIgnored(parent.getParent(), parent.getName());
      } catch (PerforceException e) {
        PerforceUIPlugin.log(e.getStatus());
      }
    }
  }
  // /** Marker resolution that adds the marker's resource to the .p4ignore
  // file. */
  private final class AddPatternToIgnoreResolutionMarker implements IMarkerResolution {
    private Shell shell;

    public AddPatternToIgnoreResolutionMarker(Shell shell) {
      this.shell = shell;
    }

    /** @see IMarkerResolution#getLabel() */
    public String getLabel() {
      return "Add pattern to .p4ignore";
    }

    /** @see IMarkerResolution#run(IMarker) */
    public void run(IMarker marker) {
      final IFile file = (IFile) marker.getResource();
      try {
        String pattern = getPattern(file.getName());
        PerforceSynchronizer.getInstance().addIgnored(file.getParent(), pattern);
      } catch (PerforceException e) {
        PerforceUIPlugin.log(e.getStatus());
      }
    }

    private String getPattern(String start) {
      InputDialog dlg =
          new InputDialog(shell, "QuickFix", "Pattern to add to .p4ignore", start,
              new IInputValidator() {

                public String isValid(String newText) {
                  if (newText.length() == 0) return "Empty pattern is not permitted.";
                  return null;
                }
              });
      if (dlg.open() == InputDialog.OK) return dlg.getValue();
      return "";
    }
  }

  /** Marker resolution that adds the marker's resource to the .p4ignore file. */
  private final class AddToIgnoreResolutionMarker implements IMarkerResolution {
    /** @see IMarkerResolution#getLabel() */
    public String getLabel() {
      return "Add to .p4ignore";
    }

    /** @see IMarkerResolution#run(IMarker) */
    public void run(IMarker marker) {
      final IFile file = (IFile) marker.getResource();
      try {
        PerforceSynchronizer.getInstance().addIgnored(file.getParent(), file.getName());
      } catch (PerforceException e) {
        PerforceUIPlugin.log(e.getStatus());
      }
    }
  }

  /**
   * Marker resolution that adds the marker's resource to perforce source
   * control.
   */
  private final class AddToSourceControlResolution implements IMarkerResolution {
    /** @see IMarkerResolution#getLabel() */
    public String getLabel() {
      return "Add to Source Control";
    }

    /** @see IMarkerResolution#run(IMarker) */
    public void run(final IMarker marker) {
      try {
        P4AddResolutionGenerator.this.run(new IRunnableWithProgress() {
          @SuppressWarnings("unused")
          // InterruptedException
          public void run(IProgressMonitor monitor) throws InvocationTargetException,
              InterruptedException {
            monitor.setTaskName("Add To Source Control...");

            final IFile file = (IFile) marker.getResource();
            final IP4TeamProvider provider =
                (IP4TeamProvider) RepositoryProvider.getProvider(file.getProject(),
                    PerforceCorePlugin.getTypeId());

            try {
              provider.openForAdd(new IResource[] {file}, IResource.DEPTH_ZERO, monitor);
            } catch (PerforceException e) {
              throw new InvocationTargetException(e);
            }
          }
        });
      } catch (InterruptedException e) {
        PerforceUIPlugin.logError("P4AddResolutionGenerator.run() failed", e);
      } catch (InvocationTargetException e) {
        Throwable cause = e.getTargetException();
        if (cause instanceof PerforceException) {
          PerforceUIPlugin.log(((PerforceException) cause).getStatus());
        } else {
          PerforceUIPlugin.logError("P4AddResolutionGenerator.run() failed", e);
        }
      }
    }
  }

  public boolean hasResolutions(IMarker marker) {
    return true;
  }
}
